package network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Iterator;
import java.util.Vector;

import network.messages.AbstractMessage;
import network.messages.MessageFactory;

/**
 * classe parent pour tous les sockets (Client et Serveur). Cette classe est
 * abstraite
 * 
 * @author Antoine Gassot
 */
public abstract class AbstractSocket implements Runnable {
    /**
     * L'IP du serveur
     */
    protected static final String ip = "127.0.0.1";

    /**
     * Le port du serveur
     */
    protected static int port = 6666;

    /**
     * Le socket, il sera instancié dans la méthode abstraite createSocket
     */
    protected Socket socket;

    /**
     * Un vecteur d'écouteurs, qui seront avertis quand un message arrivera
     */
    protected Vector<NetworkListener> listeners;

    /**
     * Flux de sortie du socket. Wrappé autour du flux primaire, trop lourd à
     * utiliser
     */
    protected BufferedWriter outputStream;

    /**
     * Flux d'entrée du socket.
     */
    protected BufferedReader inputStream;

    /**
     * Le thread de l'instance
     */
    
    private String buffer;
    protected Thread thread;

    /**
     * Constructeur - Instancie le socket
     * 
     * @throws IOException si le socket n'est pas bien connecté.
     */
    public AbstractSocket() throws IOException {
	creerSocket();
        outputStream = new BufferedWriter(new OutputStreamWriter(socket
                .getOutputStream()));
        inputStream = new BufferedReader(new InputStreamReader(socket
                .getInputStream()));

        listeners = new Vector<NetworkListener>();

        thread = new Thread(this);
        thread.start();
    }

    /**
     * Devra créé un socket
     * 
     * @throws IOException Survient si un problème arrive pendant la connexion
     */
    protected abstract void creerSocket() throws IOException;

    /**
     * Point d'entrée du thread
     */
    public void run() {
        while (true) {
            try {
                String string = inputStream.readLine();
                AbstractMessage message = MessageFactory.getInstance()
                        .deserialize(string);

                if (message != null) {
                    avertirArriveMessage(message);
                }
            } catch (IOException exception) {
            }
        }
    }

    /**
     * Doit transmettre un message sur le socket
     * 
     * @param message Le message à sérialiser et transmettre
     * @throws IOException Le socket a probablement un problème, l'écriture est
     *         impossible
     */
    public void envoyer(AbstractMessage message) throws IOException {
        String string = MessageFactory.getInstance().serialize(message) + "\n";
        outputStream.write(string);
        outputStream.flush();
    }

    /**
     * Ajoute un écouteur
     * 
     * @param listener
     */
    public void ajouterListener(NetworkListener listener) {
        listeners.add(listener);
    }

    /**
     * Enlève un écouteur
     * 
     * @param listener
     */
    public void enleverListener(NetworkListener listener) {
        listeners.remove(listener);
    }

    /**
     * Averti les écouteurs de l'arrivée d'un nouveau message
     * 
     * @param message
     */
    protected void avertirArriveMessage(AbstractMessage message) {
        Iterator<NetworkListener> iterator = listeners.iterator();
        while (iterator.hasNext()) {
            iterator.next().messageArrive(this, message);
        }
    }

    public void setBuffer(String buffer) {
	this.buffer = buffer;
    }

    public String getBuffer() {
	return buffer;
    }
}
